Introduction
In this report, I will explore the red wine dataset. First, I will look at each individual attribute of this dataset and plot its distribution. Second, I will look at two attributes at a time to explore 1) how each input attribute is related to the output attribute–quality; 2) interesting pairs of input attributes. Third, I will examine three attributes by adding one additional attribute to some of the interesting two-attribute pairs. Finally, I will summarize the successes and problems I encounter during the data exploration process.
# Load all of the packages in this code chunk.
library(ggplot2)
library(corrplot)
library(RColorBrewer)
library(memisc)
# Load all of the packages in this code chunk.
library(ggplot2)
library(corrplot)
library(RColorBrewer)
library(memisc)
Univariate Exploration
In this section, I will first look at the structure of the data set. Then I will examine the distribution of each attribute individually by plotting its distribution.
dim(wine_reds)
# Convert quality into ordered categorical variable
wine_reds$quality <- ordered(wine_reds$quality)
str(wine_reds)
summary(wine_reds)
The red wine dataset contains 12 variables–11 input numerical variables based on physicochemical tests and 1 categorical output variable (quality) based on sensory data, with 1599 observations.
# Load the Data
wine_reds = read.csv('wineQualityReds.csv', row.names = 1)
Quality
dim(wine_reds)
[1] 1599 12
Out of the possible quality scores between 0 and 10, all of our red wines’ quality scores fall between 3 and 8. The dataset is not well balanced. Majority of red wines have a quality score of either 5 or 6. I am curious about what attributes make a wine earn a low quality score (quality = 3) or a high quality score (quality = 8).
Fixed Acidity
Most acids involved with wine are fixed or nonvolatile (do not evaporate readily).
# Convert quality into ordered categorical variable
wine_reds$quality <- ordered(wine_reds$quality)
str(wine_reds)
'data.frame': 1599 obs. of 12 variables:
$ fixed.acidity : num 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
$ volatile.acidity : num 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...
$ citric.acid : num 0 0 0.04 0.56 0 0 0.06 0 0.02 0.36 ...
$ residual.sugar : num 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
$ chlorides : num 0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.071 ...
$ free.sulfur.dioxide : num 11 25 15 17 11 13 15 15 9 17 ...
$ total.sulfur.dioxide: num 34 67 54 60 34 40 59 21 18 102 ...
$ density : num 0.998 0.997 0.997 0.998 0.998 ...
$ pH : num 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
$ sulphates : num 0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.8 ...
$ alcohol : num 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
$ quality : Ord.factor w/ 6 levels "3"<"4"<"5"<"6"<..: 3 3 3 4 3 3 3 5 5 3 ...
Fixed acidity values range between 4 and 16, with most values range between 7 and 9. The distribution is slightly positively skewed. Transforming the x-axis into log scale can make it more normally distributed.
Volatile Acidity
The amount of acetic acid in wine, which at too high of levels can lead to an unpleasant, vinegar taste.
summary(wine_reds)
fixed.acidity volatile.acidity citric.acid residual.sugar chlorides
Min. : 4.60 Min. :0.1200 Min. :0.000 Min. : 0.900 Min. :0.01200
1st Qu.: 7.10 1st Qu.:0.3900 1st Qu.:0.090 1st Qu.: 1.900 1st Qu.:0.07000
Median : 7.90 Median :0.5200 Median :0.260 Median : 2.200 Median :0.07900
Mean : 8.32 Mean :0.5278 Mean :0.271 Mean : 2.539 Mean :0.08747
3rd Qu.: 9.20 3rd Qu.:0.6400 3rd Qu.:0.420 3rd Qu.: 2.600 3rd Qu.:0.09000
Max. :15.90 Max. :1.5800 Max. :1.000 Max. :15.500 Max. :0.61100
free.sulfur.dioxide total.sulfur.dioxide density pH
Min. : 1.00 Min. : 6.00 Min. :0.9901 Min. :2.740
1st Qu.: 7.00 1st Qu.: 22.00 1st Qu.:0.9956 1st Qu.:3.210
Median :14.00 Median : 38.00 Median :0.9968 Median :3.310
Mean :15.87 Mean : 46.47 Mean :0.9967 Mean :3.311
3rd Qu.:21.00 3rd Qu.: 62.00 3rd Qu.:0.9978 3rd Qu.:3.400
Max. :72.00 Max. :289.00 Max. :1.0037 Max. :4.010
sulphates alcohol quality
Min. :0.3300 Min. : 8.40 3: 10
1st Qu.:0.5500 1st Qu.: 9.50 4: 53
Median :0.6200 Median :10.20 5:681
Mean :0.6581 Mean :10.42 6:638
3rd Qu.:0.7300 3rd Qu.:11.10 7:199
Max. :2.0000 Max. :14.90 8: 18
Fixed acidity values range between 0.1 and 1.6, with most values range between 0.3 and 0.7. The distribution is slightly positively skewed. When zoom in to values below 1, the distribution seems normal.
Citric Acid
Found in small quantities, citric acid can add ‘freshness’ and flavor to wines.
# Function to plot histogram of a single variable
plot_uni_var <- function(variable, bins = 50) {
return (ggplot(aes_string(x = variable), data = wine_reds) +
geom_histogram(bins = bins))
}
ggplot(aes(x = quality), data = wine_reds) +
geom_bar()

Citric acid values range between 0 and 1 with most values below 0.6. There are 132 red wines in our data set with no detectable citric acid concentration.
Residual Sugar
The amount of sugar remaining after fermentation stops, it is rare to find wines with less than 1 gram/liter and wines with greater than 45 grams/liter are considered sweet.
plot_uni_var('fixed.acidity')

plot_uni_var('fixed.acidity') + scale_x_log10()

Most residual sugar values range between 1.5 and 2.5. There are a few outliers with large values. When zoom in and look at values below 5, the distribution appears normal.
Chlorides
The amount of salt in the wine.
plot_uni_var('volatile.acidity')

plot_uni_var('volatile.acidity') + scale_x_continuous(limits = c(0, 1))

Most chlorides values range between 0.05 to 0.1. There are a few outliers with large values. When zoom in and look at values below 0.2, the distribution appears normal.
Free Sulfur Dioxide
The free form of SO2 exists in equilibrium between molecular SO2 (as a dissolved gas) and bisulfite ion; it prevents microbial growth and the oxidation of wine.
plot_uni_var('citric.acid')

The distribution of free sulfur dioxide is highly positively skewed.
Total Sulfur Dioxide
The amount of free and bound forms of S02; in low concentrations, SO2 is mostly undetectable in wine, but at free SO2 concentrations over 50 ppm, SO2 becomes evident in the nose and taste of wine.
# number of red wines with citric acid = 0
dim(wine_reds[wine_reds$citric.acid ==0, ])[1]
[1] 132
The distribution of total sulfur dioxide is higly positively skewed. And there are a few outliers with very large values. Transforming the x-axis into log scale can make it more normally distributed.
Density
The density of wine is close to that of water depending on the percent alcohol and sugar content.
plot_uni_var('residual.sugar')

plot_uni_var('residual.sugar') + scale_x_continuous(limits = c(0, 5))

Density values range between 0.990 and 1.004 with most values range from 0.995 and 0.998. The distribution of density values are symmetrical centered around 0.9965.
pH
Describes how acidic or basic a wine is on a scale from 0 (very acidic) to 14 (very basic); most wines are between 3-4 on the pH scale.
plot_uni_var('chlorides')

plot_uni_var('chlorides') + scale_x_continuous(limits = c(0, 0.2))

Most pH values range between 3.15 and 3.45. The distribution of pH is symmetrical centered around 3.3.
Sulphates
A wine additive which can contribute to sulfur dioxide gas (S02) levels, wich acts as an antimicrobial and antioxidant.
plot_uni_var('free.sulfur.dioxide')

Most sulphates values range between 0.5 and 0.75. The distribution is positively skewed. There are a few ourliers with large sulphates values. Transforming the x-axis into log scale can make it more normally distributed.
Alcohol
The percent alcohol content of the wine
plot_uni_var('total.sulfur.dioxide')

plot_uni_var('total.sulfur.dioxide') + scale_x_log10()

The alcohol values range between 8.5 and 15. The distribution of alcohol value is positively skewed.
Univariate Analysis
What is the structure of your dataset?
There are 12 attributes in the dataset. 11 of them (fixed acidity, volatile acidity, citric acid, residual sugar, chlorides, free sulfur dioxide, total sulfur dioxide, density, pH, sulphates, alcohol) are input attributes based on physicochemical tests. The other attribute (quality) is the output attribute based on sensory data. Each row corresponds to one particular wine with total 1599 different red wines in the data set.
What is/are the main feature(s) of interest in your dataset?
The main feature of interest is the output attribute quality. I am trying to figure out which of the 11 input attribute contribute to a high quality value.
What other features in the dataset do you think will help support your investigation into your feature(s) of interest?
The 11 input attributes are equally likely to contribute to the quality value at this point. I will look more closely at how each of the attributes is distributed with a given quality value in the bivariate exploration section.
Did you create any new variables from existing variables in the dataset?
No.
Of the features you investigated, were there any unusual distributions? Did you perform any operations on the data to tidy, adjust, or change the form of the data? If so, why did you do this?
The possible quality values are from 0 to 10, but our data set only has quality values from 3 to 8, which means there are no extremely bad red wines or extrememly good wines in out data set. The vast majority of red wines in the data set has a quality value either 5 or 6, with very fewer wines with quality values 3, 4, 7 or 8, which makes the data set unbalanced.
Bivariate Exploration Part I
In this section, I will look at how each input attribute is related to the output quanlity variable.
plot_uni_var('density')

Quality vs Fixed Acidity
plot_uni_var('pH')

There isn’t a clear trend between fixed acidity and quality.
Quality vs Volatile Acidity
plot_uni_var('sulphates')

plot_uni_var('sulphates') + scale_x_log10()

The higher the quality, the lower the volatile acidity.
Quality vs Citric Acid
plot_uni_var('alcohol')

The higher the quality, the higher the citric acid.
Quality vs Residual Sugar
# Function to plot boxplot of variable grouped by quality
plot_quality_vs_var <- function(variable) {
# Uncomment the next line to print a summary of variable grouped by quality values
# print (by(wine_reds[[variable]], wine_reds$quality, summary))
return (ggplot(aes_string(x = 'quality', y = variable), data = wine_reds) +
geom_boxplot())
}
There isn’t a clear trend between residual sugar and quality.
Quality vs Chlorides
plot_quality_vs_var('fixed.acidity')

After zoom in, one can see the higher the quality, the lower the chlorides.
Quality vs Free Sulfur Dioxide
plot_quality_vs_var('volatile.acidity')

There isn’t a clear trend between free sulfur dioxide and quality.
Quality vs Total Sulfur Dioxide
plot_quality_vs_var('citric.acid')

There isn’t a clear trend between total sulfur dioxide and quality.
Quality vs Density
plot_quality_vs_var('residual.sugar')

The higher the quality, the lower the density.
Quality vs pH
plot_quality_vs_var('chlorides')

plot_quality_vs_var('chlorides') + scale_y_continuous(limits = c(0.05, 0.15))

The higher the quality, the lower the pH.
Quality vs Sulphates
plot_quality_vs_var('free.sulfur.dioxide')

The higher the quality, the higher the sulphates.
Quality vs Alcohol
plot_quality_vs_var('total.sulfur.dioxide')

The higher the quality, the higher the alcohol.
Bivariate Exploration Part II
In this section, I will first plot the correlation matrix to find out if there are any interesting pairs of input attributes that look interesting. Then I will examine these pairs.
Correlation Matrix
plot_quality_vs_var('density')

There are a few pairs of input variables deserve further examing from the correlation matrix plot: fixed acidity vs citric acid, fixed acidity vs density, fixed acidity vs pH, volatile acidity vs citric acid, citric acid vs pH, total sulfur dioxide vs free sulfur dioxide, density vs alcohol.
plot_quality_vs_var('pH')

Fixed Acidity vs Citric Acid
plot_quality_vs_var('sulphates')

Fixed acidity and citric acid have a correlation coefficient of 0.6717034. This is probably because citric acid is also a kind of fixed acidity.
Volatile Acidity vs Citric Acid
plot_quality_vs_var('alcohol')

Volatile acidity and citric acid have a correlation coefficient of -0.5524957. I cannot think of an explaination for this correlation.
pH vs log10(Fixed Acidity)
cor_matrix <- cor(wine_reds[, 1:11])
corrplot(cor_matrix, type = 'lower')

The pH scale is logarithmic, so I first transform fixed acidity into log10(fixed acidity). log10(fixed acidity) and pH have a correlation coefficient of -0.7063602. This is because hihger fixed acidity concentration leads to lower pH values.
pH vs Citric Acid
# Function to plot scatter plot of variable2 vs variable1
plot_bi_var <- function(variable1, variable2) {
return (ggplot(aes_string(x = variable1, y = variable2), data = wine_reds) +
geom_point(alpha = 1/4, position = position_jitter(width = 0)))
}
Citric acid and pH have a correlation coefficient of -0.5419041. Because we have 132 wines with 0 citric acid values, we cannot perform a logarithmic transfrom here. The correaltion is due to citric acid is non volatile, therefore higher citiric acid concentration leads to lower pH value.
Total Sulfur Dioxide vs Free Sulfur Dioxide
plot_bi_var('citric.acid', 'fixed.acidity')

cor(wine_reds$citric.acid, wine_reds$fixed.acidity)
[1] 0.6717034
Total sulfur dioxide and free sulfur dioxide have a correlation coefficient of 0.6676665. This is because free sulfur dioxide is part of total sulfur dioxide, and this can also be seen from all the points are above the y=x line.
Density vs Alcohol
plot_bi_var('citric.acid', 'volatile.acidity')

cor(wine_reds$citric.acid, wine_reds$volatile.acidity)
[1] -0.5524957
Density and alcohol have a correlation coefficient of -0.4961798. This is probably because alcohol has a lower density comparing to water. Therefore, the higher concentration of alcohol, the lower the wine density is.
Density vs Fixed Acidity
plot_bi_var('log10(fixed.acidity)', 'pH')

cor(log10(wine_reds$fixed.acidity), wine_reds$pH)
[1] -0.7063602
Densidy and fixed acidity have a correlation coefficient of 0.6680473. This is probably because fixed acidity in wine is mainly tartaric acid, and tartaric acid has a density of 1.79 g/mL, which is greater than the wine’s main component–water. Therefore, higher concentration of fixed acidity leads to higher density value.
Bivariate Analysis
Talk about some of the relationships you observed in this part of the investigation. How did the feature(s) of interest vary with other features in the dataset?
There are a few attributes exhibit some trends that look promising to be used to predict quality.
- Quality is positively correlated with citric acid, sulphates, and alcohol.
- Quality increases is negatively correlated with volatile acidity, chlorides, density, and pH.
We can summarize these relations in the following table:
| fixed acidity |
~ |
| volatile acidity |
- |
| citric acid |
+ |
| residual sugar |
~ |
| chlorides |
- |
| free sulfur dioxide |
~ |
| total sulfur dioxide |
~ |
| density |
- |
| pH |
- |
| sulphates |
+ |
| alcohol |
+ |
- ‘~’ means the attribute exhibits no clear trend with quality
- ‘-’ means the attribute is negatively correlated with quality
- ‘+’ means the attribute is positively correlated with quality
Did you observe any interesting relationships between the other features (not the main feature(s) of interest)?
There are a few attributes that are correlated based on physical and chemical principles:
- Fixed acidity and citric acid are positively correlated because the fixed acidity includes citric acid.
- Total sulfur dioxide and free sulfur dioxide are positively correlated because total sulfur dioxide includes free sulfur dioxide.
- Fixed acidity and pH are negatively correlated because higher concentration of fixed acidity makes the wine more acidic, therefore the wine has a lower pH.
- Citric acid and pH are negatively correlated because higher concentration of citric acid, which is non-volatile, makes the wine more acidic, therefore the wine has a lower pH.
- Density and alcohol are negatively correlated because alcohol has a lower density than water, therefore wines that contain more alcohol have a lower density.
- Density and fixed acidity are positively correlated because the main fixed acids in wine, tartaric acid, has a higher density than water, therefore wines that contain more tartaric acid have a higher density.
What was the strongest relationship you found?
Observing from the plot, volatile acidity has the strongest relationship with quality.
Multivariate Exploration Part I
In this section, I will first look at how quality, volatile acidity and one other input variable are related.
plot_bi_var('citric.acid', 'pH')

cor(wine_reds$citric.acid, wine_reds$pH)
[1] -0.5419041
Quality vs Volatile Acidity and Citric Acid
plot_bi_var('free.sulfur.dioxide', 'total.sulfur.dioxide') + geom_abline(slope=1)

cor(wine_reds$free.sulfur.dioxide, wine_reds$total.sulfur.dioxide)
[1] 0.6676665
High quality wines tend to have low volatile acidity and high citric acid (upper left corner); low quality wines tend to have high volatile acidity and low citric acid ( lower right corner).
Quality vs Volatile Acidity and Sulphates
plot_bi_var('alcohol', 'density')

cor(wine_reds$alcohol, wine_reds$density)
[1] -0.4961798
High quality wines tend to have low volatile acidity and high sulphates (lower right corner); low quality wines tend to have high volatile acidity and low sulphates (upper left corner).
Quality vs Volatile Acidity and Alcohol
plot_bi_var('fixed.acidity', 'density')

cor(wine_reds$fixed.acidity, wine_reds$density)
[1] 0.6680473
High quality wines tend to have low volatile acidity and high alcohol (lower right corner); low quality wines tend to have high volatile acidity and low alcohol (upper left corner).
Quality vs Volatile Acidity and Chlorides
# Function to plot scatter plot of variable2 vs variable1 colored by quality
plot_quality_vs_two_var <- function(variable1, variable2) {
ggplot(aes_string(x = variable1, y = variable2, color = 'quality'), data = wine_reds) +
geom_jitter(alpha = 1/2) +
scale_color_brewer(type = 'div')
}
High quality wines tend to have low volatile acidity and low chlorides (lower left corner); low quality wines tend to have high volatile acidity and high chlorides (upper right corner).
Quality vs Volatile Acidity and Density
plot_quality_vs_two_var('volatile.acidity', 'citric.acid')

High quality wines tend to have low volatile acidity and low density (lower left corner); low quality wines tend to have high volatile acidity and high density (upper right corner).
Quality vs Volatile Acidity and pH
plot_quality_vs_two_var('sulphates', 'volatile.acidity')

High quality wines tend to have low volatile acidity and low pH (lower left corner); low quality wines tend to have high volatile acidity and high pH (upper right corner).
Multivariate Exploration Part II
In this section, I will examine the relation among some of input variable triplets.
plot_quality_vs_two_var('alcohol', 'volatile.acidity')

plot_quality_vs_two_var('chlorides', 'volatile.acidity') +
scale_x_continuous(limits = c(0, 0.2))

pH vs Fixed Acidity and Citric Acid
plot_quality_vs_two_var('density', 'volatile.acidity')

Fixed acidity and citric acid both contribute to wines’ pH values. The lower both acids concentrations, the higher the pH (lower left corner), and the higher both acides concentrations, the lower the pH (upper right corner).
Density vs Alcohol and Fixed Acidity
plot_quality_vs_two_var('pH', 'volatile.acidity')

Fixed acidity is positively correlated with density, and alcohol is negatively correlated with density. We can see from the plot that fixed acidity has a larger impact on the density of wine than alcohol. Because for a given alcohol value, the density increases as fixed acidity increases, whereas for a given fixed acidity value, the density does not change as the alcohol increases.
Linear Models
In order to fit a linear model, I will convert quality from ordered factors back into real numbers.
- First model I will only look at the most promising attribute volatile acidity from univariate exploration section.
- Seconde model I will add the attributes that exhibit a clear trend with quality from the bivariate exploration section besides volatile acidity.
- Third model I will add all the rest variables.
# Function to cut given column from wine_reds data set into quartiles
cut_quartiles <- function(var_to_cut) {
return (cut(wine_reds[[var_to_cut]],
breaks = quantile(wine_reds[[var_to_cut]],
probs = seq(0, 1, 0.25),
na.rm = TRUE),
include.lowest = TRUE))
}
As one can see, the most promising attribute volatile acidicy alone has R-squared value of 0.153. By adding the other 6 promsing attributes, R-squared value is a little more than doubled becoming 0.350. But adding the rest 4 attributes only increases the R-squared value a little to 0.361.
Multivariate Analysis
Talk about some of the relationships you observed in this part of the investigation. Were there features that strengthened each other in terms of looking at your feature(s) of interest?
By combining the most promising attribute from bivariate section, volatile acidity, with one of the other attributes (citric acid, sulphates, alcohol, chlorides, density and pH), one can further separate high quality wines and low quality wines.
Were there any interesting or surprising interactions between features?
By looking at density vs fixed acidity and alcohol, one can see that fixed acidity has a larger impact on the density of the wine than alcohol.
OPTIONAL: Did you create any models with your dataset? Discuss the strengths and limitations of your model.
I created three linear models to predict the output attribute quality. The strength of the model is that it is a simple linear model and it is easy to interpret. However, because the quality values are discrete integer values, the model is less accurate comparing to a more nuanced continuous quality value model. Also due to the limitation of the dataset, only physical and chemical attributes are available, and other import attributes, such as price, color, smell, etc are missing. The other attributes may influence the quality values to a large extent.
Final Plots
Plot I
# Function to plot scatter plot of variable2 vs variable1 colored by variable3
plot_tri_var <- function(variable1, variable2, variable3){
ggplot(aes_string(x = variable1, y = variable2, color = variable3),
data = wine_reds) +
geom_jitter() +
scale_color_brewer(type = 'seq') +
theme_dark()
}
The possible quality values are ranging from 0 to 10, however, all red wines in the dataset have quality values between 3 and 8. There is no any really bad wine with quality below 3 or any really good wine with quality above 8. Also, most of the red wines have quality 5 or 6, which make the dataset not well balanced.
Plot II
wine_reds$pH_quantiles <- cut_quantiles('pH')
plot_tri_var('citric.acid', 'fixed.acidity', 'pH_quantiles')

Excluding the upper 1% outliers, one can see from the plot that higher quality wines (dark green) tend to have low volatile acidity and high sulphates (lower right corner), while lower quality wines (dark brown) tend to have high volatile acidity and low sulphates (upper left corner).
Plot III
wine_reds$density_quartiles <- cut_quartiles('density')
plot_tri_var('alcohol', 'fixed.acidity', 'density_quartiles')

Fixed acidity is positively correlated with density, and alcohol is negatively correlated with density. The fixed acidity has a larger impact on the density of wine than alcohol. Because for a given alcohol value, the density increases (from light blue to dark blue) as fixed acidity increases, whereas for a given fixed acidity value, the density does not change much as the alcohol increases.
Reflection
The red wine data set has 11 input physicochemical attributes and 1 quality output attribute. Throughout the analysis, I focused on answering two quations:
- How are different input physicochemical attributes related to the quality output attribute?
- Are there interesting relations among input physicochemical attributes?
I ran into difficulties when answering question 1. There were many combinations of the 11 input attributes I could pick to plot against the quality attribute. But I did not have good criteria to determine the order of importance of these attributes. I relied on visualization and chose the volatile acidicy as the most promising attribute and used it as the fixed attribute during multivariate plot section.
I did observe some good results when answering question 2. The plots showing between and among different input physicochemical attributes were in accordance with actual physical and chemical properties and laws, such high acid concentration correlates with low pH, and high alcohol percent correlates with low density.
I believe by incorporating other types of attributes, such as price, color and smell, I can build a better model to predict the quality of wine than using only physicochemical attributes. Also, one more interesting project can be combining the red wine data set with the white wine data set, and to find out if attributes correlate to high quality red wines also correlate to high quality white wines.
LS0tCnRpdGxlOiAiRXhwbG9yZSBSZWQgV2luZSBEYXRhIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBzZWxmX2NvbnRhaW5lZDogbm8KICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwotLS0KCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIHJlcG9ydCwgSSB3aWxsIGV4cGxvcmUgdGhlIHJlZCB3aW5lIGRhdGFzZXQuIEZpcnN0LCBJIHdpbGwgbG9vayBhdCBlYWNoIGluZGl2aWR1YWwgYXR0cmlidXRlIG9mIHRoaXMgZGF0YXNldCBhbmQgcGxvdCBpdHMgZGlzdHJpYnV0aW9uLiBTZWNvbmQsIEkgd2lsbCBsb29rIGF0IHR3byBhdHRyaWJ1dGVzIGF0IGEgdGltZSB0byBleHBsb3JlIDEpIGhvdyBlYWNoIGlucHV0IGF0dHJpYnV0ZSBpcyByZWxhdGVkIHRvIHRoZSBvdXRwdXQgYXR0cmlidXRlLS1xdWFsaXR5OyAyKSBpbnRlcmVzdGluZyBwYWlycyBvZiBpbnB1dCBhdHRyaWJ1dGVzLiBUaGlyZCwgSSB3aWxsIGV4YW1pbmUgdGhyZWUgYXR0cmlidXRlcyBieSBhZGRpbmcgb25lIGFkZGl0aW9uYWwgYXR0cmlidXRlIHRvIHNvbWUgb2YgdGhlIGludGVyZXN0aW5nIHR3by1hdHRyaWJ1dGUgcGFpcnMuIEZpbmFsbHksIEkgd2lsbCBzdW1tYXJpemUgdGhlIHN1Y2Nlc3NlcyBhbmQgcHJvYmxlbXMgSSBlbmNvdW50ZXIgZHVyaW5nIHRoZSBkYXRhIGV4cGxvcmF0aW9uIHByb2Nlc3MuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgcGFja2FnZXN9CiMgTG9hZCBhbGwgb2YgdGhlIHBhY2thZ2VzIGluIHRoaXMgY29kZSBjaHVuay4KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvcnJwbG90KQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShtZW1pc2MpCmBgYAoKYGBge3J9CiMgTG9hZCB0aGUgRGF0YQp3aW5lX3JlZHMgPSByZWFkLmNzdignd2luZVF1YWxpdHlSZWRzLmNzdicsIHJvdy5uYW1lcyA9IDEpCmBgYAoKIyBVbml2YXJpYXRlIEV4cGxvcmF0aW9uCgpJbiB0aGlzIHNlY3Rpb24sIEkgd2lsbCBmaXJzdCBsb29rIGF0IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgc2V0LiBUaGVuIEkgd2lsbCBleGFtaW5lIHRoZSBkaXN0cmlidXRpb24gb2YgZWFjaCBhdHRyaWJ1dGUgaW5kaXZpZHVhbGx5IGJ5IHBsb3R0aW5nIGl0cyBkaXN0cmlidXRpb24uCgpgYGB7ciwgRGF0YV9EaW1lbnNpb25zfQpkaW0od2luZV9yZWRzKQpgYGAKCmBgYHtyLCBEYXRhX1N0cnVjdHVyZX0KIyBDb252ZXJ0IHF1YWxpdHkgaW50byBvcmRlcmVkIGNhdGVnb3JpY2FsIHZhcmlhYmxlCndpbmVfcmVkcyRxdWFsaXR5IDwtIG9yZGVyZWQod2luZV9yZWRzJHF1YWxpdHkpCnN0cih3aW5lX3JlZHMpCmBgYAoKYGBge3IsIERhdGFfU3VtbWFyeX0Kc3VtbWFyeSh3aW5lX3JlZHMpCmBgYAoKVGhlIHJlZCB3aW5lIGRhdGFzZXQgY29udGFpbnMgMTIgdmFyaWFibGVzLS0xMSBpbnB1dCBudW1lcmljYWwgdmFyaWFibGVzIGJhc2VkIG9uIHBoeXNpY29jaGVtaWNhbCB0ZXN0cyBhbmQgMSBjYXRlZ29yaWNhbCBvdXRwdXQgdmFyaWFibGUgKHF1YWxpdHkpIGJhc2VkIG9uIHNlbnNvcnkgZGF0YSwgd2l0aCAxNTk5IG9ic2VydmF0aW9ucy4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgaGlzdG9ncmFtIG9mIGEgc2luZ2xlIHZhcmlhYmxlCnBsb3RfdW5pX3ZhciA8LSBmdW5jdGlvbih2YXJpYWJsZSwgYmlucyA9IDUwKSB7CiAgcmV0dXJuIChnZ3Bsb3QoYWVzX3N0cmluZyh4ID0gdmFyaWFibGUpLCBkYXRhID0gd2luZV9yZWRzKSArIAogICAgICAgICAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gYmlucykpCn0KYGBgCgojIyBRdWFsaXR5CmBgYHtyfQpnZ3Bsb3QoYWVzKHggPSBxdWFsaXR5KSwgZGF0YSA9IHdpbmVfcmVkcykgKyAKICBnZW9tX2JhcigpCmBgYAoKT3V0IG9mIHRoZSBwb3NzaWJsZSBxdWFsaXR5IHNjb3JlcyBiZXR3ZWVuIDAgYW5kIDEwLCBhbGwgb2Ygb3VyIHJlZCB3aW5lcycgcXVhbGl0eSBzY29yZXMgZmFsbCBiZXR3ZWVuIDMgYW5kIDguIFRoZSBkYXRhc2V0IGlzIG5vdCB3ZWxsIGJhbGFuY2VkLiBNYWpvcml0eSBvZiByZWQgd2luZXMgaGF2ZSBhIHF1YWxpdHkgc2NvcmUgb2YgZWl0aGVyIDUgb3IgNi4gSSBhbSBjdXJpb3VzIGFib3V0IHdoYXQgYXR0cmlidXRlcyBtYWtlIGEgd2luZSBlYXJuIGEgbG93IHF1YWxpdHkgc2NvcmUgKHF1YWxpdHkgPSAzKSBvciBhIGhpZ2ggcXVhbGl0eSBzY29yZSAocXVhbGl0eSA9IDgpLgoKIyMgRml4ZWQgQWNpZGl0eQpNb3N0IGFjaWRzIGludm9sdmVkIHdpdGggd2luZSBhcmUgZml4ZWQgb3Igbm9udm9sYXRpbGUgKGRvIG5vdCBldmFwb3JhdGUgcmVhZGlseSkuCmBgYHtyfQpwbG90X3VuaV92YXIoJ2ZpeGVkLmFjaWRpdHknKQpwbG90X3VuaV92YXIoJ2ZpeGVkLmFjaWRpdHknKSArIHNjYWxlX3hfbG9nMTAoKQpgYGAKCkZpeGVkIGFjaWRpdHkgdmFsdWVzIHJhbmdlIGJldHdlZW4gNCBhbmQgMTYsIHdpdGggbW9zdCB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiA3IGFuZCA5LiBUaGUgZGlzdHJpYnV0aW9uIGlzIHNsaWdodGx5IHBvc2l0aXZlbHkgc2tld2VkLiBUcmFuc2Zvcm1pbmcgdGhlIHgtYXhpcyBpbnRvIGxvZyBzY2FsZSBjYW4gbWFrZSBpdCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgVm9sYXRpbGUgQWNpZGl0eQpUaGUgYW1vdW50IG9mIGFjZXRpYyBhY2lkIGluIHdpbmUsIHdoaWNoIGF0IHRvbyBoaWdoIG9mIGxldmVscyBjYW4gbGVhZCB0byBhbiB1bnBsZWFzYW50LCB2aW5lZ2FyIHRhc3RlLgpgYGB7cn0KcGxvdF91bmlfdmFyKCd2b2xhdGlsZS5hY2lkaXR5JykKcGxvdF91bmlfdmFyKCd2b2xhdGlsZS5hY2lkaXR5JykgKyBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSkKYGBgCgpGaXhlZCBhY2lkaXR5IHZhbHVlcyByYW5nZSBiZXR3ZWVuIDAuMSBhbmQgMS42LCB3aXRoIG1vc3QgdmFsdWVzIHJhbmdlIGJldHdlZW4gMC4zIGFuZCAwLjcuIFRoZSBkaXN0cmlidXRpb24gaXMgc2xpZ2h0bHkgcG9zaXRpdmVseSBza2V3ZWQuIFdoZW4gem9vbSBpbiB0byB2YWx1ZXMgYmVsb3cgMSwgdGhlIGRpc3RyaWJ1dGlvbiBzZWVtcyBub3JtYWwuCgojIyBDaXRyaWMgQWNpZApGb3VuZCBpbiBzbWFsbCBxdWFudGl0aWVzLCBjaXRyaWMgYWNpZCBjYW4gYWRkICdmcmVzaG5lc3MnIGFuZCBmbGF2b3IgdG8gd2luZXMuCmBgYHtyfQpwbG90X3VuaV92YXIoJ2NpdHJpYy5hY2lkJykKYGBgCgpgYGB7cn0KIyBudW1iZXIgb2YgcmVkIHdpbmVzIHdpdGggY2l0cmljIGFjaWQgPSAwCmRpbSh3aW5lX3JlZHNbd2luZV9yZWRzJGNpdHJpYy5hY2lkID09MCwgXSlbMV0KYGBgCgpDaXRyaWMgYWNpZCB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiAwIGFuZCAxIHdpdGggbW9zdCB2YWx1ZXMgYmVsb3cgMC42LiBUaGVyZSBhcmUgMTMyIHJlZCB3aW5lcyBpbiBvdXIgZGF0YSBzZXQgd2l0aCBubyBkZXRlY3RhYmxlIGNpdHJpYyBhY2lkIGNvbmNlbnRyYXRpb24uCgojIyBSZXNpZHVhbCBTdWdhcgpUaGUgYW1vdW50IG9mIHN1Z2FyIHJlbWFpbmluZyBhZnRlciBmZXJtZW50YXRpb24gc3RvcHMsIGl0IGlzIHJhcmUgdG8gZmluZCB3aW5lcyB3aXRoIGxlc3MgdGhhbiAxIGdyYW0vbGl0ZXIgYW5kIHdpbmVzIHdpdGggZ3JlYXRlciB0aGFuIDQ1IGdyYW1zL2xpdGVyIGFyZSBjb25zaWRlcmVkIHN3ZWV0LgpgYGB7cn0KcGxvdF91bmlfdmFyKCdyZXNpZHVhbC5zdWdhcicpCnBsb3RfdW5pX3ZhcigncmVzaWR1YWwuc3VnYXInKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDUpKQpgYGAKCk1vc3QgcmVzaWR1YWwgc3VnYXIgdmFsdWVzIHJhbmdlIGJldHdlZW4gMS41IGFuZCAyLjUuIFRoZXJlIGFyZSBhIGZldyBvdXRsaWVycyB3aXRoIGxhcmdlIHZhbHVlcy4gV2hlbiB6b29tIGluIGFuZCBsb29rIGF0IHZhbHVlcyBiZWxvdyA1LCB0aGUgZGlzdHJpYnV0aW9uIGFwcGVhcnMgbm9ybWFsLgoKIyMgQ2hsb3JpZGVzClRoZSBhbW91bnQgb2Ygc2FsdCBpbiB0aGUgd2luZS4KYGBge3J9CnBsb3RfdW5pX3ZhcignY2hsb3JpZGVzJykKcGxvdF91bmlfdmFyKCdjaGxvcmlkZXMnKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDAuMikpCmBgYAoKTW9zdCBjaGxvcmlkZXMgdmFsdWVzIHJhbmdlIGJldHdlZW4gMC4wNSB0byAwLjEuIFRoZXJlIGFyZSBhIGZldyBvdXRsaWVycyB3aXRoIGxhcmdlIHZhbHVlcy4gV2hlbiB6b29tIGluIGFuZCBsb29rIGF0IHZhbHVlcyBiZWxvdyAwLjIsIHRoZSBkaXN0cmlidXRpb24gYXBwZWFycyBub3JtYWwuCgojIyBGcmVlIFN1bGZ1ciBEaW94aWRlClRoZSBmcmVlIGZvcm0gb2YgU08yIGV4aXN0cyBpbiBlcXVpbGlicml1bSBiZXR3ZWVuIG1vbGVjdWxhciBTTzIgKGFzIGEgZGlzc29sdmVkIGdhcykgYW5kIGJpc3VsZml0ZSBpb247IGl0IHByZXZlbnRzIG1pY3JvYmlhbCBncm93dGggYW5kIHRoZSBveGlkYXRpb24gb2Ygd2luZS4KYGBge3J9CnBsb3RfdW5pX3ZhcignZnJlZS5zdWxmdXIuZGlveGlkZScpCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBmcmVlIHN1bGZ1ciBkaW94aWRlIGlzIGhpZ2hseSBwb3NpdGl2ZWx5IHNrZXdlZC4KCiMjIFRvdGFsIFN1bGZ1ciBEaW94aWRlClRoZSBhbW91bnQgb2YgZnJlZSBhbmQgYm91bmQgZm9ybXMgb2YgUzAyOyBpbiBsb3cgY29uY2VudHJhdGlvbnMsIFNPMiBpcyBtb3N0bHkgdW5kZXRlY3RhYmxlIGluIHdpbmUsIGJ1dCBhdCBmcmVlIFNPMiBjb25jZW50cmF0aW9ucyBvdmVyIDUwIHBwbSwgU08yIGJlY29tZXMgZXZpZGVudCBpbiB0aGUgbm9zZSBhbmQgdGFzdGUgb2Ygd2luZS4KCmBgYHtyfQpwbG90X3VuaV92YXIoJ3RvdGFsLnN1bGZ1ci5kaW94aWRlJykKcGxvdF91bmlfdmFyKCd0b3RhbC5zdWxmdXIuZGlveGlkZScpICsgc2NhbGVfeF9sb2cxMCgpCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiB0b3RhbCBzdWxmdXIgZGlveGlkZSBpcyBoaWdseSBwb3NpdGl2ZWx5IHNrZXdlZC4gQW5kIHRoZXJlIGFyZSBhIGZldyBvdXRsaWVycyB3aXRoIHZlcnkgbGFyZ2UgdmFsdWVzLiBUcmFuc2Zvcm1pbmcgdGhlIHgtYXhpcyBpbnRvIGxvZyBzY2FsZSBjYW4gbWFrZSBpdCBtb3JlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgRGVuc2l0eQpUaGUgZGVuc2l0eSBvZiB3aW5lIGlzIGNsb3NlIHRvIHRoYXQgb2Ygd2F0ZXIgZGVwZW5kaW5nIG9uIHRoZSBwZXJjZW50IGFsY29ob2wgYW5kIHN1Z2FyIGNvbnRlbnQuCmBgYHtyfQpwbG90X3VuaV92YXIoJ2RlbnNpdHknKQpgYGAKCkRlbnNpdHkgdmFsdWVzIHJhbmdlIGJldHdlZW4gMC45OTAgYW5kIDEuMDA0IHdpdGggbW9zdCB2YWx1ZXMgcmFuZ2UgZnJvbSAwLjk5NSBhbmQgMC45OTguIFRoZSBkaXN0cmlidXRpb24gb2YgZGVuc2l0eSB2YWx1ZXMgYXJlIHN5bW1ldHJpY2FsIGNlbnRlcmVkIGFyb3VuZCAwLjk5NjUuCgojIyBwSApEZXNjcmliZXMgaG93IGFjaWRpYyBvciBiYXNpYyBhIHdpbmUgaXMgb24gYSBzY2FsZSBmcm9tIDAgKHZlcnkgYWNpZGljKSB0byAxNCAodmVyeSBiYXNpYyk7IG1vc3Qgd2luZXMgYXJlIGJldHdlZW4gMy00IG9uIHRoZSBwSCBzY2FsZS4KYGBge3J9CnBsb3RfdW5pX3ZhcigncEgnKQpgYGAKCk1vc3QgcEggdmFsdWVzIHJhbmdlIGJldHdlZW4gMy4xNSBhbmQgMy40NS4gVGhlIGRpc3RyaWJ1dGlvbiBvZiBwSCBpcyBzeW1tZXRyaWNhbCBjZW50ZXJlZCBhcm91bmQgMy4zLgoKIyMgU3VscGhhdGVzCkEgd2luZSBhZGRpdGl2ZSB3aGljaCBjYW4gY29udHJpYnV0ZSB0byBzdWxmdXIgZGlveGlkZSBnYXMgKFMwMikgbGV2ZWxzLCB3aWNoIGFjdHMgYXMgYW4gYW50aW1pY3JvYmlhbCBhbmQgYW50aW94aWRhbnQuCmBgYHtyfQpwbG90X3VuaV92YXIoJ3N1bHBoYXRlcycpCnBsb3RfdW5pX3Zhcignc3VscGhhdGVzJykgKyBzY2FsZV94X2xvZzEwKCkKYGBgCgpNb3N0IHN1bHBoYXRlcyB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiAwLjUgYW5kIDAuNzUuIFRoZSBkaXN0cmlidXRpb24gaXMgcG9zaXRpdmVseSBza2V3ZWQuIFRoZXJlIGFyZSBhIGZldyBvdXJsaWVycyB3aXRoIGxhcmdlIHN1bHBoYXRlcyB2YWx1ZXMuIFRyYW5zZm9ybWluZyB0aGUgeC1heGlzIGludG8gbG9nIHNjYWxlIGNhbiBtYWtlIGl0IG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgojIyBBbGNvaG9sClRoZSBwZXJjZW50IGFsY29ob2wgY29udGVudCBvZiB0aGUgd2luZQpgYGB7cn0KcGxvdF91bmlfdmFyKCdhbGNvaG9sJykKYGBgCgpUaGUgYWxjb2hvbCB2YWx1ZXMgcmFuZ2UgYmV0d2VlbiA4LjUgYW5kIDE1LiBUaGUgZGlzdHJpYnV0aW9uIG9mIGFsY29ob2wgdmFsdWUgaXMgcG9zaXRpdmVseSBza2V3ZWQuCgojIFVuaXZhcmlhdGUgQW5hbHlzaXMKCioqV2hhdCBpcyB0aGUgc3RydWN0dXJlIG9mIHlvdXIgZGF0YXNldD8qKgoKVGhlcmUgYXJlIDEyIGF0dHJpYnV0ZXMgaW4gdGhlIGRhdGFzZXQuIDExIG9mIHRoZW0gKGZpeGVkIGFjaWRpdHksIHZvbGF0aWxlIGFjaWRpdHksIGNpdHJpYyBhY2lkLCByZXNpZHVhbCBzdWdhciwgY2hsb3JpZGVzLCBmcmVlIHN1bGZ1ciBkaW94aWRlLCB0b3RhbCBzdWxmdXIgZGlveGlkZSwgZGVuc2l0eSwgcEgsIHN1bHBoYXRlcywgYWxjb2hvbCkgYXJlIGlucHV0IGF0dHJpYnV0ZXMgYmFzZWQgb24gcGh5c2ljb2NoZW1pY2FsIHRlc3RzLiBUaGUgb3RoZXIgYXR0cmlidXRlIChxdWFsaXR5KSBpcyB0aGUgb3V0cHV0IGF0dHJpYnV0ZSBiYXNlZCBvbiBzZW5zb3J5IGRhdGEuIEVhY2ggcm93IGNvcnJlc3BvbmRzIHRvIG9uZSBwYXJ0aWN1bGFyIHdpbmUgd2l0aCB0b3RhbCAxNTk5IGRpZmZlcmVudCByZWQgd2luZXMgaW4gdGhlIGRhdGEgc2V0LgoKKipXaGF0IGlzL2FyZSB0aGUgbWFpbiBmZWF0dXJlKHMpIG9mIGludGVyZXN0IGluIHlvdXIgZGF0YXNldD8qKgoKVGhlIG1haW4gZmVhdHVyZSBvZiBpbnRlcmVzdCBpcyB0aGUgb3V0cHV0IGF0dHJpYnV0ZSBxdWFsaXR5LiBJIGFtIHRyeWluZyB0byBmaWd1cmUgb3V0IHdoaWNoIG9mIHRoZSAxMSBpbnB1dCBhdHRyaWJ1dGUgY29udHJpYnV0ZSB0byBhIGhpZ2ggcXVhbGl0eSB2YWx1ZS4KCioqV2hhdCBvdGhlciBmZWF0dXJlcyBpbiB0aGUgZGF0YXNldCBkbyB5b3UgdGhpbmsgd2lsbCBoZWxwIHN1cHBvcnQgeW91ciBpbnZlc3RpZ2F0aW9uIGludG8geW91ciBmZWF0dXJlKHMpIG9mIGludGVyZXN0PyoqCgpUaGUgMTEgaW5wdXQgYXR0cmlidXRlcyBhcmUgZXF1YWxseSBsaWtlbHkgdG8gY29udHJpYnV0ZSB0byB0aGUgcXVhbGl0eSB2YWx1ZSBhdCB0aGlzIHBvaW50LiBJIHdpbGwgbG9vayBtb3JlIGNsb3NlbHkgYXQgaG93IGVhY2ggb2YgdGhlIGF0dHJpYnV0ZXMgaXMgZGlzdHJpYnV0ZWQgd2l0aCBhIGdpdmVuIHF1YWxpdHkgdmFsdWUgaW4gdGhlIGJpdmFyaWF0ZSBleHBsb3JhdGlvbiBzZWN0aW9uLgoKKipEaWQgeW91IGNyZWF0ZSBhbnkgbmV3IHZhcmlhYmxlcyBmcm9tIGV4aXN0aW5nIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldD8qKgoKTm8uCgoqKk9mIHRoZSBmZWF0dXJlcyB5b3UgaW52ZXN0aWdhdGVkLCB3ZXJlIHRoZXJlIGFueSB1bnVzdWFsIGRpc3RyaWJ1dGlvbnM/IERpZCB5b3UgcGVyZm9ybSBhbnkgb3BlcmF0aW9ucyBvbiB0aGUgZGF0YSB0byB0aWR5LCBhZGp1c3QsIG9yIGNoYW5nZSB0aGUgZm9ybSBvZiB0aGUgZGF0YT8gSWYgc28sIHdoeSBkaWQgeW91IGRvIHRoaXM/KioKClRoZSBwb3NzaWJsZSBxdWFsaXR5IHZhbHVlcyBhcmUgZnJvbSAwIHRvIDEwLCBidXQgb3VyIGRhdGEgc2V0IG9ubHkgaGFzIHF1YWxpdHkgdmFsdWVzIGZyb20gMyB0byA4LCB3aGljaCBtZWFucyB0aGVyZSBhcmUgbm8gZXh0cmVtZWx5IGJhZCByZWQgd2luZXMgb3IgZXh0cmVtZW1seSBnb29kIHdpbmVzIGluIG91dCBkYXRhIHNldC4gVGhlIHZhc3QgbWFqb3JpdHkgb2YgcmVkIHdpbmVzIGluIHRoZSBkYXRhIHNldCBoYXMgYSBxdWFsaXR5IHZhbHVlIGVpdGhlciA1IG9yIDYsIHdpdGggdmVyeSBmZXdlciB3aW5lcyB3aXRoIHF1YWxpdHkgdmFsdWVzIDMsIDQsIDcgb3IgOCwgd2hpY2ggbWFrZXMgdGhlIGRhdGEgc2V0IHVuYmFsYW5jZWQuCgojIEJpdmFyaWF0ZSBFeHBsb3JhdGlvbiBQYXJ0IEkKCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGxvb2sgYXQgaG93IGVhY2ggaW5wdXQgYXR0cmlidXRlIGlzIHJlbGF0ZWQgdG8gdGhlIG91dHB1dCBxdWFubGl0eSB2YXJpYWJsZS4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgYm94cGxvdCBvZiB2YXJpYWJsZSBncm91cGVkIGJ5IHF1YWxpdHkKcGxvdF9xdWFsaXR5X3ZzX3ZhciA8LSBmdW5jdGlvbih2YXJpYWJsZSkgewogICMgVW5jb21tZW50IHRoZSBuZXh0IGxpbmUgdG8gcHJpbnQgYSBzdW1tYXJ5IG9mIHZhcmlhYmxlIGdyb3VwZWQgYnkgcXVhbGl0eSB2YWx1ZXMKICAjIHByaW50IChieSh3aW5lX3JlZHNbW3ZhcmlhYmxlXV0sIHdpbmVfcmVkcyRxdWFsaXR5LCBzdW1tYXJ5KSkKICByZXR1cm4gKGdncGxvdChhZXNfc3RyaW5nKHggPSAncXVhbGl0eScsIHkgPSB2YXJpYWJsZSksIGRhdGEgPSB3aW5lX3JlZHMpICsgCiAgICAgICAgICAgIGdlb21fYm94cGxvdCgpKQp9CmBgYAoKIyMgUXVhbGl0eSB2cyBGaXhlZCBBY2lkaXR5CmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdmaXhlZC5hY2lkaXR5JykKYGBgCgpUaGVyZSBpc24ndCBhIGNsZWFyIHRyZW5kIGJldHdlZW4gZml4ZWQgYWNpZGl0eSBhbmQgcXVhbGl0eS4KCiMjIFF1YWxpdHkgdnMgVm9sYXRpbGUgQWNpZGl0eQpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3Zhcigndm9sYXRpbGUuYWNpZGl0eScpCmBgYAoKVGhlIGhpZ2hlciB0aGUgcXVhbGl0eSwgdGhlIGxvd2VyIHRoZSB2b2xhdGlsZSBhY2lkaXR5LgoKIyMgUXVhbGl0eSB2cyBDaXRyaWMgQWNpZApgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3ZhcignY2l0cmljLmFjaWQnKQpgYGAKClRoZSBoaWdoZXIgdGhlIHF1YWxpdHksIHRoZSBoaWdoZXIgdGhlIGNpdHJpYyBhY2lkLgoKIyMgUXVhbGl0eSB2cyBSZXNpZHVhbCBTdWdhcgpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3ZhcigncmVzaWR1YWwuc3VnYXInKQpgYGAKClRoZXJlIGlzbid0IGEgY2xlYXIgdHJlbmQgYmV0d2VlbiByZXNpZHVhbCBzdWdhciBhbmQgcXVhbGl0eS4KCiMjIFF1YWxpdHkgdnMgQ2hsb3JpZGVzCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdjaGxvcmlkZXMnKQpwbG90X3F1YWxpdHlfdnNfdmFyKCdjaGxvcmlkZXMnKSArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuMDUsIDAuMTUpKQpgYGAKCkFmdGVyIHpvb20gaW4sIG9uZSBjYW4gc2VlIHRoZSBoaWdoZXIgdGhlIHF1YWxpdHksIHRoZSBsb3dlciB0aGUgY2hsb3JpZGVzLgoKIyMgUXVhbGl0eSB2cyBGcmVlIFN1bGZ1ciBEaW94aWRlCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdmcmVlLnN1bGZ1ci5kaW94aWRlJykKYGBgCgpUaGVyZSBpc24ndCBhIGNsZWFyIHRyZW5kIGJldHdlZW4gZnJlZSBzdWxmdXIgZGlveGlkZSBhbmQgcXVhbGl0eS4KCiMjIFF1YWxpdHkgdnMgVG90YWwgU3VsZnVyIERpb3hpZGUKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ3RvdGFsLnN1bGZ1ci5kaW94aWRlJykKYGBgCgpUaGVyZSBpc24ndCBhIGNsZWFyIHRyZW5kIGJldHdlZW4gdG90YWwgc3VsZnVyIGRpb3hpZGUgYW5kIHF1YWxpdHkuCgojIyBRdWFsaXR5IHZzIERlbnNpdHkKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ2RlbnNpdHknKQpgYGAKClRoZSBoaWdoZXIgdGhlIHF1YWxpdHksIHRoZSBsb3dlciB0aGUgZGVuc2l0eS4KCiMjIFF1YWxpdHkgdnMgcEgKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ3BIJykKYGBgCgpUaGUgaGlnaGVyIHRoZSBxdWFsaXR5LCB0aGUgbG93ZXIgdGhlIHBILgoKIyMgUXVhbGl0eSB2cyBTdWxwaGF0ZXMKYGBge3J9CnBsb3RfcXVhbGl0eV92c192YXIoJ3N1bHBoYXRlcycpCmBgYAoKVGhlIGhpZ2hlciB0aGUgcXVhbGl0eSwgdGhlIGhpZ2hlciB0aGUgc3VscGhhdGVzLgoKIyMgUXVhbGl0eSB2cyBBbGNvaG9sCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdmFyKCdhbGNvaG9sJykKYGBgCgpUaGUgaGlnaGVyIHRoZSBxdWFsaXR5LCB0aGUgaGlnaGVyIHRoZSBhbGNvaG9sLgoKIyBCaXZhcmlhdGUgRXhwbG9yYXRpb24gUGFydCBJSQoKSW4gdGhpcyBzZWN0aW9uLCBJIHdpbGwgZmlyc3QgcGxvdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IHRvIGZpbmQgb3V0IGlmIHRoZXJlIGFyZSBhbnkgaW50ZXJlc3RpbmcgcGFpcnMgb2YgaW5wdXQgYXR0cmlidXRlcyB0aGF0IGxvb2sgaW50ZXJlc3RpbmcuIFRoZW4gSSB3aWxsIGV4YW1pbmUgdGhlc2UgcGFpcnMuCgojIyBDb3JyZWxhdGlvbiBNYXRyaXgKYGBge3J9CmNvcl9tYXRyaXggPC0gY29yKHdpbmVfcmVkc1ssIDE6MTFdKQpjb3JycGxvdChjb3JfbWF0cml4LCB0eXBlID0gJ2xvd2VyJykKYGBgCgpUaGVyZSBhcmUgYSBmZXcgcGFpcnMgb2YgaW5wdXQgdmFyaWFibGVzIGRlc2VydmUgZnVydGhlciBleGFtaW5nIGZyb20gdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBwbG90OiBmaXhlZCBhY2lkaXR5IHZzIGNpdHJpYyBhY2lkLCBmaXhlZCBhY2lkaXR5IHZzIGRlbnNpdHksIGZpeGVkIGFjaWRpdHkgdnMgcEgsIHZvbGF0aWxlIGFjaWRpdHkgdnMgY2l0cmljIGFjaWQsIGNpdHJpYyBhY2lkIHZzIHBILCB0b3RhbCBzdWxmdXIgZGlveGlkZSB2cyBmcmVlIHN1bGZ1ciBkaW94aWRlLCBkZW5zaXR5IHZzIGFsY29ob2wuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IHNjYXR0ZXIgcGxvdCBvZiB2YXJpYWJsZTIgdnMgdmFyaWFibGUxCnBsb3RfYmlfdmFyIDwtIGZ1bmN0aW9uKHZhcmlhYmxlMSwgdmFyaWFibGUyKSB7CiAgcmV0dXJuIChnZ3Bsb3QoYWVzX3N0cmluZyh4ID0gdmFyaWFibGUxLCB5ID0gdmFyaWFibGUyKSwgZGF0YSA9IHdpbmVfcmVkcykgKyAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAxLzQsIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gMCkpKQp9CmBgYAoKIyMgRml4ZWQgQWNpZGl0eSB2cyBDaXRyaWMgQWNpZApgYGB7cn0KcGxvdF9iaV92YXIoJ2NpdHJpYy5hY2lkJywgJ2ZpeGVkLmFjaWRpdHknKQpjb3Iod2luZV9yZWRzJGNpdHJpYy5hY2lkLCB3aW5lX3JlZHMkZml4ZWQuYWNpZGl0eSkKYGBgCgpGaXhlZCBhY2lkaXR5IGFuZCBjaXRyaWMgYWNpZCBoYXZlIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgMC42NzE3MDM0LiBUaGlzIGlzIHByb2JhYmx5IGJlY2F1c2UgY2l0cmljIGFjaWQgaXMgYWxzbyBhIGtpbmQgb2YgZml4ZWQgYWNpZGl0eS4KCiMjIFZvbGF0aWxlIEFjaWRpdHkgdnMgQ2l0cmljIEFjaWQKYGBge3J9CnBsb3RfYmlfdmFyKCdjaXRyaWMuYWNpZCcsICd2b2xhdGlsZS5hY2lkaXR5JykKY29yKHdpbmVfcmVkcyRjaXRyaWMuYWNpZCwgd2luZV9yZWRzJHZvbGF0aWxlLmFjaWRpdHkpCmBgYAoKVm9sYXRpbGUgYWNpZGl0eSBhbmQgY2l0cmljIGFjaWQgaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIC0wLjU1MjQ5NTcuIEkgY2Fubm90IHRoaW5rIG9mIGFuIGV4cGxhaW5hdGlvbiBmb3IgdGhpcyBjb3JyZWxhdGlvbi4gCgojIyBwSCB2cyBsb2cxMChGaXhlZCBBY2lkaXR5KQpgYGB7cn0KcGxvdF9iaV92YXIoJ2xvZzEwKGZpeGVkLmFjaWRpdHkpJywgJ3BIJykKY29yKGxvZzEwKHdpbmVfcmVkcyRmaXhlZC5hY2lkaXR5KSwgd2luZV9yZWRzJHBIKQpgYGAKClRoZSBwSCBzY2FsZSBpcyBsb2dhcml0aG1pYywgc28gSSBmaXJzdCB0cmFuc2Zvcm0gZml4ZWQgYWNpZGl0eSBpbnRvIGxvZzEwKGZpeGVkIGFjaWRpdHkpLiBsb2cxMChmaXhlZCBhY2lkaXR5KSBhbmQgcEggaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIC0wLjcwNjM2MDIuIFRoaXMgaXMgYmVjYXVzZSBoaWhnZXIgZml4ZWQgYWNpZGl0eSBjb25jZW50cmF0aW9uIGxlYWRzIHRvIGxvd2VyIHBIIHZhbHVlcy4KCiMjIHBIIHZzIENpdHJpYyBBY2lkCmBgYHtyfQpwbG90X2JpX3ZhcignY2l0cmljLmFjaWQnLCAncEgnKQpjb3Iod2luZV9yZWRzJGNpdHJpYy5hY2lkLCB3aW5lX3JlZHMkcEgpCmBgYAoKQ2l0cmljIGFjaWQgYW5kIHBIIGhhdmUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAtMC41NDE5MDQxLiBCZWNhdXNlIHdlIGhhdmUgMTMyIHdpbmVzIHdpdGggMCBjaXRyaWMgYWNpZCB2YWx1ZXMsIHdlIGNhbm5vdCBwZXJmb3JtIGEgbG9nYXJpdGhtaWMgdHJhbnNmcm9tIGhlcmUuIFRoZSBjb3JyZWFsdGlvbiBpcyBkdWUgdG8gY2l0cmljIGFjaWQgaXMgbm9uIHZvbGF0aWxlLCB0aGVyZWZvcmUgaGlnaGVyIGNpdGlyaWMgYWNpZCBjb25jZW50cmF0aW9uIGxlYWRzIHRvIGxvd2VyIHBIIHZhbHVlLgoKIyMgVG90YWwgU3VsZnVyIERpb3hpZGUgdnMgRnJlZSBTdWxmdXIgRGlveGlkZQpgYGB7cn0KcGxvdF9iaV92YXIoJ2ZyZWUuc3VsZnVyLmRpb3hpZGUnLCAndG90YWwuc3VsZnVyLmRpb3hpZGUnKSArIGdlb21fYWJsaW5lKHNsb3BlPTEpCmNvcih3aW5lX3JlZHMkZnJlZS5zdWxmdXIuZGlveGlkZSwgd2luZV9yZWRzJHRvdGFsLnN1bGZ1ci5kaW94aWRlKQpgYGAKClRvdGFsIHN1bGZ1ciBkaW94aWRlIGFuZCBmcmVlIHN1bGZ1ciBkaW94aWRlIGhhdmUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAwLjY2NzY2NjUuIFRoaXMgaXMgYmVjYXVzZSBmcmVlIHN1bGZ1ciBkaW94aWRlIGlzIHBhcnQgb2YgdG90YWwgc3VsZnVyIGRpb3hpZGUsIGFuZCB0aGlzIGNhbiBhbHNvIGJlIHNlZW4gZnJvbSBhbGwgdGhlIHBvaW50cyBhcmUgYWJvdmUgdGhlIHk9eCBsaW5lLgoKIyMgRGVuc2l0eSB2cyBBbGNvaG9sCmBgYHtyfQpwbG90X2JpX3ZhcignYWxjb2hvbCcsICdkZW5zaXR5JykKY29yKHdpbmVfcmVkcyRhbGNvaG9sLCB3aW5lX3JlZHMkZGVuc2l0eSkKYGBgCgpEZW5zaXR5IGFuZCBhbGNvaG9sIGhhdmUgYSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBvZiAtMC40OTYxNzk4LiBUaGlzIGlzIHByb2JhYmx5IGJlY2F1c2UgYWxjb2hvbCBoYXMgYSBsb3dlciBkZW5zaXR5IGNvbXBhcmluZyB0byB3YXRlci4gVGhlcmVmb3JlLCB0aGUgaGlnaGVyIGNvbmNlbnRyYXRpb24gb2YgYWxjb2hvbCwgdGhlIGxvd2VyIHRoZSB3aW5lIGRlbnNpdHkgaXMuCgojIyBEZW5zaXR5IHZzIEZpeGVkIEFjaWRpdHkKYGBge3J9CnBsb3RfYmlfdmFyKCdmaXhlZC5hY2lkaXR5JywgJ2RlbnNpdHknKQpjb3Iod2luZV9yZWRzJGZpeGVkLmFjaWRpdHksIHdpbmVfcmVkcyRkZW5zaXR5KQpgYGAKCkRlbnNpZHkgYW5kIGZpeGVkIGFjaWRpdHkgaGF2ZSBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIDAuNjY4MDQ3My4gVGhpcyBpcyBwcm9iYWJseSBiZWNhdXNlIGZpeGVkIGFjaWRpdHkgaW4gd2luZSBpcyBtYWlubHkgdGFydGFyaWMgYWNpZCwgYW5kIHRhcnRhcmljIGFjaWQgaGFzIGEgZGVuc2l0eSBvZiAxLjc5IGcvbUwsIHdoaWNoIGlzIGdyZWF0ZXIgdGhhbiB0aGUgd2luZSdzIG1haW4gY29tcG9uZW50LS13YXRlci4gVGhlcmVmb3JlLCBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBmaXhlZCBhY2lkaXR5IGxlYWRzIHRvIGhpZ2hlciBkZW5zaXR5IHZhbHVlLgoKIyBCaXZhcmlhdGUgQW5hbHlzaXMKCioqVGFsayBhYm91dCBzb21lIG9mIHRoZSByZWxhdGlvbnNoaXBzIHlvdSBvYnNlcnZlZCBpbiB0aGlzIHBhcnQgb2YgdGhlIGludmVzdGlnYXRpb24uIEhvdyBkaWQgdGhlIGZlYXR1cmUocykgb2YgaW50ZXJlc3QgdmFyeSB3aXRoIG90aGVyIGZlYXR1cmVzIGluIHRoZSBkYXRhc2V0PyoqCgpUaGVyZSBhcmUgYSBmZXcgYXR0cmlidXRlcyBleGhpYml0IHNvbWUgdHJlbmRzIHRoYXQgbG9vayBwcm9taXNpbmcgdG8gYmUgdXNlZCB0byBwcmVkaWN0IHF1YWxpdHkuIAoKKiBRdWFsaXR5IGlzIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIGNpdHJpYyBhY2lkLCBzdWxwaGF0ZXMsIGFuZCBhbGNvaG9sLgoqIFF1YWxpdHkgaW5jcmVhc2VzIGlzIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHZvbGF0aWxlIGFjaWRpdHksIGNobG9yaWRlcywgZGVuc2l0eSwgYW5kIHBILgoKV2UgY2FuIHN1bW1hcml6ZSB0aGVzZSByZWxhdGlvbnMgaW4gdGhlIGZvbGxvd2luZyB0YWJsZToKCnwgQXR0cmlidXRlIE5hbWUgICAgICAgfCBSZWxhdGlvbiB3aXRoIFF1YWxpdHkgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCBmaXhlZCBhY2lkaXR5ICAgICAgICB8ICAgICAgICAgICB+ICAgICAgICAgICB8Cnwgdm9sYXRpbGUgYWNpZGl0eSAgICAgfCAgICAgICAgICAgLSAgICAgICAgICAgfAp8IGNpdHJpYyBhY2lkICAgICAgICAgIHwgICAgICAgICAgICsgICAgICAgICAgIHwKfCByZXNpZHVhbCBzdWdhciAgICAgICB8ICAgICAgICAgICB+ICAgICAgICAgICB8CnwgY2hsb3JpZGVzICAgICAgICAgICAgfCAgICAgICAgICAgLSAgICAgICAgICAgfAp8IGZyZWUgc3VsZnVyIGRpb3hpZGUgIHwgICAgICAgICAgIH4gICAgICAgICAgIHwKfCB0b3RhbCBzdWxmdXIgZGlveGlkZSB8ICAgICAgICAgICB+ICAgICAgICAgICB8CnwgZGVuc2l0eSAgICAgICAgICAgICAgfCAgICAgICAgICAgLSAgICAgICAgICAgfAp8IHBIICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgIC0gICAgICAgICAgIHwKfCBzdWxwaGF0ZXMgICAgICAgICAgICB8ICAgICAgICAgICArICAgICAgICAgICB8CnwgYWxjb2hvbCAgICAgICAgICAgICAgfCAgICAgICAgICAgKyAgICAgICAgICAgfAoKKiAnficgbWVhbnMgdGhlIGF0dHJpYnV0ZSBleGhpYml0cyBubyBjbGVhciB0cmVuZCB3aXRoIHF1YWxpdHkKKiAnLScgbWVhbnMgdGhlIGF0dHJpYnV0ZSBpcyBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBxdWFsaXR5CiogJysnIG1lYW5zIHRoZSBhdHRyaWJ1dGUgaXMgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggcXVhbGl0eQoKKipEaWQgeW91IG9ic2VydmUgYW55IGludGVyZXN0aW5nIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgb3RoZXIgZmVhdHVyZXMgKG5vdCB0aGUgbWFpbiBmZWF0dXJlKHMpIG9mIGludGVyZXN0KT8qKgoKVGhlcmUgYXJlIGEgZmV3IGF0dHJpYnV0ZXMgdGhhdCBhcmUgY29ycmVsYXRlZCBiYXNlZCBvbiBwaHlzaWNhbCBhbmQgY2hlbWljYWwgcHJpbmNpcGxlczoKCiogRml4ZWQgYWNpZGl0eSBhbmQgY2l0cmljIGFjaWQgYXJlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCBiZWNhdXNlIHRoZSBmaXhlZCBhY2lkaXR5IGluY2x1ZGVzIGNpdHJpYyBhY2lkLgoqIFRvdGFsIHN1bGZ1ciBkaW94aWRlIGFuZCBmcmVlIHN1bGZ1ciBkaW94aWRlIGFyZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSB0b3RhbCBzdWxmdXIgZGlveGlkZSBpbmNsdWRlcyBmcmVlIHN1bGZ1ciBkaW94aWRlLgoqIEZpeGVkIGFjaWRpdHkgYW5kIHBIIGFyZSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBmaXhlZCBhY2lkaXR5IG1ha2VzIHRoZSB3aW5lIG1vcmUgYWNpZGljLCB0aGVyZWZvcmUgdGhlIHdpbmUgaGFzIGEgbG93ZXIgcEguCiogQ2l0cmljIGFjaWQgYW5kIHBIIGFyZSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBjaXRyaWMgYWNpZCwgd2hpY2ggaXMgbm9uLXZvbGF0aWxlLCBtYWtlcyB0aGUgd2luZSBtb3JlIGFjaWRpYywgdGhlcmVmb3JlIHRoZSB3aW5lIGhhcyBhIGxvd2VyIHBILgoqIERlbnNpdHkgYW5kIGFsY29ob2wgYXJlIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCBiZWNhdXNlIGFsY29ob2wgaGFzIGEgbG93ZXIgZGVuc2l0eSB0aGFuIHdhdGVyLCB0aGVyZWZvcmUgd2luZXMgdGhhdCBjb250YWluIG1vcmUgYWxjb2hvbCBoYXZlIGEgbG93ZXIgZGVuc2l0eS4KKiBEZW5zaXR5IGFuZCBmaXhlZCBhY2lkaXR5IGFyZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgYmVjYXVzZSB0aGUgbWFpbiBmaXhlZCBhY2lkcyBpbiB3aW5lLCB0YXJ0YXJpYyBhY2lkLCBoYXMgYSBoaWdoZXIgZGVuc2l0eSB0aGFuIHdhdGVyLCB0aGVyZWZvcmUgd2luZXMgdGhhdCBjb250YWluIG1vcmUgdGFydGFyaWMgYWNpZCBoYXZlIGEgaGlnaGVyIGRlbnNpdHkuIAoKKipXaGF0IHdhcyB0aGUgc3Ryb25nZXN0IHJlbGF0aW9uc2hpcCB5b3UgZm91bmQ/KioKCk9ic2VydmluZyBmcm9tIHRoZSBwbG90LCB2b2xhdGlsZSBhY2lkaXR5IGhhcyB0aGUgc3Ryb25nZXN0IHJlbGF0aW9uc2hpcCB3aXRoIHF1YWxpdHkuCgojIE11bHRpdmFyaWF0ZSBFeHBsb3JhdGlvbiBQYXJ0IEkKCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGZpcnN0IGxvb2sgYXQgaG93IHF1YWxpdHksIHZvbGF0aWxlIGFjaWRpdHkgYW5kIG9uZSBvdGhlciBpbnB1dCB2YXJpYWJsZSBhcmUgcmVsYXRlZC4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3Qgc2NhdHRlciBwbG90IG9mIHZhcmlhYmxlMiB2cyB2YXJpYWJsZTEgY29sb3JlZCBieSBxdWFsaXR5CnBsb3RfcXVhbGl0eV92c190d29fdmFyIDwtIGZ1bmN0aW9uKHZhcmlhYmxlMSwgdmFyaWFibGUyKSB7CiAgZ2dwbG90KGFlc19zdHJpbmcoeCA9IHZhcmlhYmxlMSwgeSA9IHZhcmlhYmxlMiwgY29sb3IgPSAncXVhbGl0eScpLCBkYXRhID0gd2luZV9yZWRzKSArCiAgICBnZW9tX2ppdHRlcihhbHBoYSA9IDEvMikgKwogICAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAnZGl2JykKfQpgYGAKCiMjIFF1YWxpdHkgdnMgVm9sYXRpbGUgQWNpZGl0eSBhbmQgQ2l0cmljIEFjaWQKYGBge3J9CnBsb3RfcXVhbGl0eV92c190d29fdmFyKCd2b2xhdGlsZS5hY2lkaXR5JywgJ2NpdHJpYy5hY2lkJykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIGNpdHJpYyBhY2lkICh1cHBlciBsZWZ0IGNvcm5lcik7IGxvdyBxdWFsaXR5IHdpbmVzIHRlbmQgdG8gaGF2ZSBoaWdoIHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBjaXRyaWMgYWNpZCAoIGxvd2VyIHJpZ2h0IGNvcm5lcikuCgojIyBRdWFsaXR5IHZzIFZvbGF0aWxlIEFjaWRpdHkgYW5kIFN1bHBoYXRlcwpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3R3b192YXIoJ3N1bHBoYXRlcycsICd2b2xhdGlsZS5hY2lkaXR5JykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIHN1bHBoYXRlcyAobG93ZXIgcmlnaHQgY29ybmVyKTsgbG93IHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgbG93IHN1bHBoYXRlcyAodXBwZXIgbGVmdCBjb3JuZXIpLgoKIyMgUXVhbGl0eSB2cyBWb2xhdGlsZSBBY2lkaXR5IGFuZCBBbGNvaG9sCmBgYHtyfQpwbG90X3F1YWxpdHlfdnNfdHdvX3ZhcignYWxjb2hvbCcsICd2b2xhdGlsZS5hY2lkaXR5JykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIGFsY29ob2wgKGxvd2VyIHJpZ2h0IGNvcm5lcik7IGxvdyBxdWFsaXR5IHdpbmVzIHRlbmQgdG8gaGF2ZSBoaWdoIHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBhbGNvaG9sICh1cHBlciBsZWZ0IGNvcm5lcikuCgojIyBRdWFsaXR5IHZzIFZvbGF0aWxlIEFjaWRpdHkgYW5kIENobG9yaWRlcwpgYGB7cn0KcGxvdF9xdWFsaXR5X3ZzX3R3b192YXIoJ2NobG9yaWRlcycsICd2b2xhdGlsZS5hY2lkaXR5JykgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAwLjIpKQpgYGAKCkhpZ2ggcXVhbGl0eSB3aW5lcyB0ZW5kIHRvIGhhdmUgbG93IHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBjaGxvcmlkZXMgKGxvd2VyIGxlZnQgY29ybmVyKTsgbG93IHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgaGlnaCBjaGxvcmlkZXMgKHVwcGVyIHJpZ2h0IGNvcm5lcikuCgojIyBRdWFsaXR5IHZzIFZvbGF0aWxlIEFjaWRpdHkgYW5kIERlbnNpdHkKYGBge3J9CnBsb3RfcXVhbGl0eV92c190d29fdmFyKCdkZW5zaXR5JywgJ3ZvbGF0aWxlLmFjaWRpdHknKQpgYGAKCkhpZ2ggcXVhbGl0eSB3aW5lcyB0ZW5kIHRvIGhhdmUgbG93IHZvbGF0aWxlIGFjaWRpdHkgYW5kIGxvdyBkZW5zaXR5IChsb3dlciBsZWZ0IGNvcm5lcik7IGxvdyBxdWFsaXR5IHdpbmVzIHRlbmQgdG8gaGF2ZSBoaWdoIHZvbGF0aWxlIGFjaWRpdHkgYW5kIGhpZ2ggZGVuc2l0eSAodXBwZXIgcmlnaHQgY29ybmVyKS4KCiMjIFF1YWxpdHkgdnMgVm9sYXRpbGUgQWNpZGl0eSBhbmQgcEgKYGBge3J9CnBsb3RfcXVhbGl0eV92c190d29fdmFyKCdwSCcsICd2b2xhdGlsZS5hY2lkaXR5JykKYGBgCgpIaWdoIHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBsb3cgcEggKGxvd2VyIGxlZnQgY29ybmVyKTsgbG93IHF1YWxpdHkgd2luZXMgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgaGlnaCBwSCAodXBwZXIgcmlnaHQgY29ybmVyKS4KCiMgTXVsdGl2YXJpYXRlIEV4cGxvcmF0aW9uIFBhcnQgSUkKCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGV4YW1pbmUgdGhlIHJlbGF0aW9uIGFtb25nIHNvbWUgb2YgaW5wdXQgdmFyaWFibGUgdHJpcGxldHMuCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGN1dCBnaXZlbiBjb2x1bW4gZnJvbSB3aW5lX3JlZHMgZGF0YSBzZXQgaW50byBxdWFydGlsZXMKY3V0X3F1YXJ0aWxlcyA8LSBmdW5jdGlvbih2YXJfdG9fY3V0KSB7CiAgcmV0dXJuIChjdXQod2luZV9yZWRzW1t2YXJfdG9fY3V0XV0sIAogICAgICAgICAgICAgIGJyZWFrcyA9IHF1YW50aWxlKHdpbmVfcmVkc1tbdmFyX3RvX2N1dF1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IHNlcSgwLCAxLCAwLjI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpCn0KYGBgCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IHNjYXR0ZXIgcGxvdCBvZiB2YXJpYWJsZTIgdnMgdmFyaWFibGUxIGNvbG9yZWQgYnkgdmFyaWFibGUzCnBsb3RfdHJpX3ZhciA8LSBmdW5jdGlvbih2YXJpYWJsZTEsIHZhcmlhYmxlMiwgdmFyaWFibGUzKXsKICBnZ3Bsb3QoYWVzX3N0cmluZyh4ID0gdmFyaWFibGUxLCB5ID0gdmFyaWFibGUyLCBjb2xvciA9IHZhcmlhYmxlMyksCiAgICAgICAgIGRhdGEgPSB3aW5lX3JlZHMpICsgCiAgICBnZW9tX2ppdHRlcigpICsgCiAgICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICdzZXEnKSArIAogICAgdGhlbWVfZGFyaygpCn0KYGBgCgojIyBwSCB2cyBGaXhlZCBBY2lkaXR5IGFuZCBDaXRyaWMgQWNpZApgYGB7cn0Kd2luZV9yZWRzJHBIX3F1YXJ0aWxlcyA8LSBjdXRfcXVhcnRpbGVzKCdwSCcpCnBsb3RfdHJpX3ZhcignY2l0cmljLmFjaWQnLCAnZml4ZWQuYWNpZGl0eScsICdwSF9xdWFydGlsZXMnKQpgYGAKCkZpeGVkIGFjaWRpdHkgYW5kIGNpdHJpYyBhY2lkIGJvdGggY29udHJpYnV0ZSB0byB3aW5lcycgcEggdmFsdWVzLiBUaGUgbG93ZXIgYm90aCBhY2lkcyBjb25jZW50cmF0aW9ucywgdGhlIGhpZ2hlciB0aGUgcEggKGxvd2VyIGxlZnQgY29ybmVyKSwgYW5kIHRoZSBoaWdoZXIgYm90aCBhY2lkZXMgY29uY2VudHJhdGlvbnMsIHRoZSBsb3dlciB0aGUgcEggKHVwcGVyIHJpZ2h0IGNvcm5lcikuCgojIyBEZW5zaXR5IHZzIEFsY29ob2wgYW5kIEZpeGVkIEFjaWRpdHkKYGBge3J9CndpbmVfcmVkcyRkZW5zaXR5X3F1YXJ0aWxlcyA8LSBjdXRfcXVhcnRpbGVzKCdkZW5zaXR5JykKcGxvdF90cmlfdmFyKCdhbGNvaG9sJywgJ2ZpeGVkLmFjaWRpdHknLCAnZGVuc2l0eV9xdWFydGlsZXMnKQpgYGAKCkZpeGVkIGFjaWRpdHkgaXMgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggZGVuc2l0eSwgYW5kIGFsY29ob2wgaXMgbmVnYXRpdmVseSBjb3JyZWxhdGVkIHdpdGggZGVuc2l0eS4gV2UgY2FuIHNlZSBmcm9tIHRoZSBwbG90IHRoYXQgZml4ZWQgYWNpZGl0eSBoYXMgYSBsYXJnZXIgaW1wYWN0IG9uIHRoZSBkZW5zaXR5IG9mIHdpbmUgdGhhbiBhbGNvaG9sLiBCZWNhdXNlIGZvciBhIGdpdmVuIGFsY29ob2wgdmFsdWUsIHRoZSBkZW5zaXR5IGluY3JlYXNlcyBhcyBmaXhlZCBhY2lkaXR5IGluY3JlYXNlcywgd2hlcmVhcyBmb3IgYSBnaXZlbiBmaXhlZCBhY2lkaXR5IHZhbHVlLCB0aGUgZGVuc2l0eSBkb2VzIG5vdCBjaGFuZ2UgYXMgdGhlIGFsY29ob2wgaW5jcmVhc2VzLgoKIyBMaW5lYXIgTW9kZWxzCgpJbiBvcmRlciB0byBmaXQgYSBsaW5lYXIgbW9kZWwsIEkgd2lsbCBjb252ZXJ0IHF1YWxpdHkgZnJvbSBvcmRlcmVkIGZhY3RvcnMgYmFjayBpbnRvIHJlYWwgbnVtYmVycy4gCgoqIEZpcnN0IG1vZGVsIEkgd2lsbCBvbmx5IGxvb2sgYXQgdGhlIG1vc3QgcHJvbWlzaW5nIGF0dHJpYnV0ZSB2b2xhdGlsZSBhY2lkaXR5IGZyb20gdW5pdmFyaWF0ZSBleHBsb3JhdGlvbiBzZWN0aW9uLiAKKiBTZWNvbmRlIG1vZGVsIEkgd2lsbCBhZGQgdGhlIGF0dHJpYnV0ZXMgdGhhdCBleGhpYml0IGEgY2xlYXIgdHJlbmQgd2l0aCBxdWFsaXR5IGZyb20gdGhlIGJpdmFyaWF0ZSBleHBsb3JhdGlvbiBzZWN0aW9uIGJlc2lkZXMgdm9sYXRpbGUgYWNpZGl0eS4gCiogVGhpcmQgbW9kZWwgSSB3aWxsIGFkZCBhbGwgdGhlIHJlc3QgdmFyaWFibGVzLgoKYGBge3J9Cm0xIDwtICBsbShhcy5udW1lcmljKGxldmVscyhxdWFsaXR5KSlbcXVhbGl0eV0gfiB2b2xhdGlsZS5hY2lkaXR5LCAKICAgICAgICAgIGRhdGEgPSB3aW5lX3JlZHMpCm0yIDwtIHVwZGF0ZShtMSwgfiAuICsgdm9sYXRpbGUuYWNpZGl0eSArIGNpdHJpYy5hY2lkICsgc3VscGhhdGVzICsgYWxjb2hvbCArIAogICAgICAgICAgICAgICBjaGxvcmlkZXMgKyBkZW5zaXR5ICsgcEgpCm0zIDwtIHVwZGF0ZShtMiwgfiAuICsgZml4ZWQuYWNpZGl0eSArIHJlc2lkdWFsLnN1Z2FyICsgZnJlZS5zdWxmdXIuZGlveGlkZSArIAogICAgICAgICAgICAgICB0b3RhbC5zdWxmdXIuZGlveGlkZSkKbXRhYmxlKG0xLCBtMiwgbTMsIHNkaWdpdHMgPSAzKQpgYGAKCkFzIG9uZSBjYW4gc2VlLCB0aGUgbW9zdCBwcm9taXNpbmcgYXR0cmlidXRlIHZvbGF0aWxlIGFjaWRpY3kgYWxvbmUgaGFzIFItc3F1YXJlZCB2YWx1ZSBvZiAwLjE1My4gQnkgYWRkaW5nIHRoZSBvdGhlciA2IHByb21zaW5nIGF0dHJpYnV0ZXMsIFItc3F1YXJlZCB2YWx1ZSBpcyBhIGxpdHRsZSBtb3JlIHRoYW4gZG91YmxlZCBiZWNvbWluZyAwLjM1MC4gQnV0IGFkZGluZyB0aGUgcmVzdCA0IGF0dHJpYnV0ZXMgb25seSBpbmNyZWFzZXMgdGhlIFItc3F1YXJlZCB2YWx1ZSBhIGxpdHRsZSB0byAwLjM2MS4KCiMgTXVsdGl2YXJpYXRlIEFuYWx5c2lzCgoqKlRhbGsgYWJvdXQgc29tZSBvZiB0aGUgcmVsYXRpb25zaGlwcyB5b3Ugb2JzZXJ2ZWQgaW4gdGhpcyBwYXJ0IG9mIHRoZSBpbnZlc3RpZ2F0aW9uLiBXZXJlIHRoZXJlIGZlYXR1cmVzIHRoYXQgc3RyZW5ndGhlbmVkIGVhY2ggb3RoZXIgaW4gdGVybXMgb2YgbG9va2luZyBhdCB5b3VyIGZlYXR1cmUocykgb2YgaW50ZXJlc3Q/KioKCkJ5IGNvbWJpbmluZyB0aGUgbW9zdCBwcm9taXNpbmcgYXR0cmlidXRlIGZyb20gYml2YXJpYXRlIHNlY3Rpb24sIHZvbGF0aWxlIGFjaWRpdHksIHdpdGggb25lIG9mIHRoZSBvdGhlciBhdHRyaWJ1dGVzIChjaXRyaWMgYWNpZCwgc3VscGhhdGVzLCBhbGNvaG9sLCBjaGxvcmlkZXMsIGRlbnNpdHkgYW5kIHBIKSwgb25lIGNhbiBmdXJ0aGVyIHNlcGFyYXRlIGhpZ2ggcXVhbGl0eSB3aW5lcyBhbmQgbG93IHF1YWxpdHkgd2luZXMuCgoqKldlcmUgdGhlcmUgYW55IGludGVyZXN0aW5nIG9yIHN1cnByaXNpbmcgaW50ZXJhY3Rpb25zIGJldHdlZW4gZmVhdHVyZXM/KioKCkJ5IGxvb2tpbmcgYXQgZGVuc2l0eSB2cyBmaXhlZCBhY2lkaXR5IGFuZCBhbGNvaG9sLCBvbmUgY2FuIHNlZSB0aGF0IGZpeGVkIGFjaWRpdHkgaGFzIGEgbGFyZ2VyIGltcGFjdCBvbiB0aGUgZGVuc2l0eSBvZiB0aGUgd2luZSB0aGFuIGFsY29ob2wuCgoqKk9QVElPTkFMOiBEaWQgeW91IGNyZWF0ZSBhbnkgbW9kZWxzIHdpdGggeW91ciBkYXRhc2V0PyBEaXNjdXNzIHRoZSBzdHJlbmd0aHMgYW5kIGxpbWl0YXRpb25zIG9mIHlvdXIgbW9kZWwuKioKCkkgY3JlYXRlZCB0aHJlZSBsaW5lYXIgbW9kZWxzIHRvIHByZWRpY3QgdGhlIG91dHB1dCBhdHRyaWJ1dGUgcXVhbGl0eS4gVGhlIHN0cmVuZ3RoIG9mIHRoZSBtb2RlbCBpcyB0aGF0IGl0IGlzIGEgc2ltcGxlIGxpbmVhciBtb2RlbCBhbmQgaXQgaXMgZWFzeSB0byBpbnRlcnByZXQuIEhvd2V2ZXIsIGJlY2F1c2UgdGhlIHF1YWxpdHkgdmFsdWVzIGFyZSBkaXNjcmV0ZSBpbnRlZ2VyIHZhbHVlcywgdGhlIG1vZGVsIGlzIGxlc3MgYWNjdXJhdGUgY29tcGFyaW5nIHRvIGEgbW9yZSBudWFuY2VkIGNvbnRpbnVvdXMgcXVhbGl0eSB2YWx1ZSBtb2RlbC4gQWxzbyBkdWUgdG8gdGhlIGxpbWl0YXRpb24gb2YgdGhlIGRhdGFzZXQsIG9ubHkgcGh5c2ljYWwgYW5kIGNoZW1pY2FsIGF0dHJpYnV0ZXMgYXJlIGF2YWlsYWJsZSwgYW5kIG90aGVyIGltcG9ydCBhdHRyaWJ1dGVzLCBzdWNoIGFzIHByaWNlLCBjb2xvciwgc21lbGwsIGV0YyBhcmUgbWlzc2luZy4gVGhlIG90aGVyIGF0dHJpYnV0ZXMgbWF5IGluZmx1ZW5jZSB0aGUgcXVhbGl0eSB2YWx1ZXMgdG8gYSBsYXJnZSBleHRlbnQuCgojIEZpbmFsIFBsb3RzCiMjIFBsb3QgSQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KZ2dwbG90KGFlcyh4ID0gcXVhbGl0eSksIGRhdGEgPSB3aW5lX3JlZHMpICsgCiAgZ2VvbV9iYXIoYWVzKHkgPSAoLi5jb3VudC4uKS9zdW0oLi5jb3VudC4uKSkpICsKICBnZW9tX3RleHQoYWVzKHkgPSAoKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQoKC4uY291bnQuLikvc3VtKC4uY291bnQuLikpKSwgCiAgICAgICAgICAgIHN0YXQgPSAiY291bnQiLCAKICAgICAgICAgICAgdmp1c3QgPSAtMC4yNSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsgCiAgeGxhYignUXVhbGl0eScpICsgCiAgeWxhYignUGVyY2VudCcpICsgCiAgZ2d0aXRsZSgnUXVhbGl0eSBSZWxhdGl2ZSBGcmVxdWVuY3kgSGlzdG9ncmFtJykgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpUaGUgcG9zc2libGUgcXVhbGl0eSB2YWx1ZXMgYXJlIHJhbmdpbmcgZnJvbSAwIHRvIDEwLCBob3dldmVyLCBhbGwgcmVkIHdpbmVzIGluIHRoZSBkYXRhc2V0IGhhdmUgcXVhbGl0eSB2YWx1ZXMgYmV0d2VlbiAzIGFuZCA4LiBUaGVyZSBpcyBubyBhbnkgcmVhbGx5IGJhZCB3aW5lIHdpdGggcXVhbGl0eSBiZWxvdyAzIG9yIGFueSByZWFsbHkgZ29vZCB3aW5lIHdpdGggcXVhbGl0eSBhYm92ZSA4LiBBbHNvLCBtb3N0IG9mIHRoZSByZWQgd2luZXMgaGF2ZSBxdWFsaXR5IDUgb3IgNiwgd2hpY2ggbWFrZSB0aGUgZGF0YXNldCBub3Qgd2VsbCBiYWxhbmNlZC4gCgojIyBQbG90IElJCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpwbG90X3F1YWxpdHlfdnNfdHdvX3Zhcignc3VscGhhdGVzJywgJ3ZvbGF0aWxlLmFjaWRpdHknKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKG1pbih3aW5lX3JlZHMkc3VscGhhdGVzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhbnRpbGUod2luZV9yZWRzJHN1bHBoYXRlcywgMC45OSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMobWluKHdpbmVfcmVkcyR2b2xhdGlsZS5hY2lkaXR5KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhbnRpbGUod2luZV9yZWRzJHZvbGF0aWxlLmFjaWRpdHksIDAuOTkpKSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gJ2RpdicsIG5hbWUgPSAnUXVhbGl0eScpICsKICB4bGFiKGV4cHJlc3Npb24oU3VscGhhdGVzfihnfmRtXnstM30pKSkgKyAKICB5bGFiKGV4cHJlc3Npb24oVm9sYXRpbGV+QWNpZGl0eX4oZ35kbV57LTN9KSkpICsgCiAgZ2d0aXRsZSgnUXVhbGl0eSB2cyBWb2xhdGlsZSBBY2lkaXR5IGFuZCBTdWxwaGF0ZXMnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkV4Y2x1ZGluZyB0aGUgdXBwZXIgMSUgb3V0bGllcnMsIG9uZSBjYW4gc2VlIGZyb20gdGhlIHBsb3QgdGhhdCBoaWdoZXIgcXVhbGl0eSB3aW5lcyAoZGFyayBncmVlbikgdGVuZCB0byBoYXZlIGxvdyB2b2xhdGlsZSBhY2lkaXR5IGFuZCBoaWdoIHN1bHBoYXRlcyAobG93ZXIgcmlnaHQgY29ybmVyKSwgd2hpbGUgbG93ZXIgcXVhbGl0eSB3aW5lcyAoZGFyayBicm93bikgdGVuZCB0byBoYXZlIGhpZ2ggdm9sYXRpbGUgYWNpZGl0eSBhbmQgbG93IHN1bHBoYXRlcyAodXBwZXIgbGVmdCBjb3JuZXIpLgoKIyMgUGxvdCBJSUkKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CndpbmVfcmVkcyRwSF9xdWFydGlsZXMgPC0gY3V0X3F1YXJ0aWxlcygnZGVuc2l0eScpCnBsb3RfdHJpX3ZhcignYWxjb2hvbCcsICdmaXhlZC5hY2lkaXR5JywgJ2RlbnNpdHlfcXVhcnRpbGVzJykgKwogIHhsYWIoZXhwcmVzc2lvbihBbGNvaG9sfignJScpKSkgKyAKICB5bGFiKGV4cHJlc3Npb24oRml4ZWR+QWNpZGl0eX4oZ35kbV57LTN9KSkpICsgCiAgZ2d0aXRsZSgnRGVuc2l0eSB2cyBGaXhlZCBBY2lkaXR5IGFuZCBBbGNvaG9sJykgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihuYW1lID0gZXhwcmVzc2lvbihEZW5zaXR5fihnfmNtXnstM30pKSwgdHlwZSA9ICdzZXEnKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKRml4ZWQgYWNpZGl0eSBpcyBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBkZW5zaXR5LCBhbmQgYWxjb2hvbCBpcyBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBkZW5zaXR5LiBUaGUgZml4ZWQgYWNpZGl0eSBoYXMgYSBsYXJnZXIgaW1wYWN0IG9uIHRoZSBkZW5zaXR5IG9mIHdpbmUgdGhhbiBhbGNvaG9sLiBCZWNhdXNlIGZvciBhIGdpdmVuIGFsY29ob2wgdmFsdWUsIHRoZSBkZW5zaXR5IGluY3JlYXNlcyAoZnJvbSBsaWdodCBibHVlIHRvIGRhcmsgYmx1ZSkgYXMgZml4ZWQgYWNpZGl0eSBpbmNyZWFzZXMsIHdoZXJlYXMgZm9yIGEgZ2l2ZW4gZml4ZWQgYWNpZGl0eSB2YWx1ZSwgdGhlIGRlbnNpdHkgZG9lcyBub3QgY2hhbmdlIG11Y2ggYXMgdGhlIGFsY29ob2wgaW5jcmVhc2VzLgoKIyBSZWZsZWN0aW9uCgpUaGUgcmVkIHdpbmUgZGF0YSBzZXQgaGFzIDExIGlucHV0IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzIGFuZCAxIHF1YWxpdHkgb3V0cHV0IGF0dHJpYnV0ZS4gVGhyb3VnaG91dCB0aGUgYW5hbHlzaXMsIEkgZm9jdXNlZCBvbiBhbnN3ZXJpbmcgdHdvIHF1YXRpb25zOiAKCiogMS4gSG93IGFyZSBkaWZmZXJlbnQgaW5wdXQgcGh5c2ljb2NoZW1pY2FsIGF0dHJpYnV0ZXMgcmVsYXRlZCB0byB0aGUgcXVhbGl0eSBvdXRwdXQgYXR0cmlidXRlPyAKKiAyLiBBcmUgdGhlcmUgaW50ZXJlc3RpbmcgcmVsYXRpb25zIGFtb25nIGlucHV0IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzPwoKSSByYW4gaW50byBkaWZmaWN1bHRpZXMgd2hlbiBhbnN3ZXJpbmcgcXVlc3Rpb24gMS4gVGhlcmUgd2VyZSBtYW55IGNvbWJpbmF0aW9ucyBvZiB0aGUgMTEgaW5wdXQgYXR0cmlidXRlcyBJIGNvdWxkIHBpY2sgdG8gcGxvdCBhZ2FpbnN0IHRoZSBxdWFsaXR5IGF0dHJpYnV0ZS4gQnV0IEkgZGlkIG5vdCBoYXZlIGdvb2QgY3JpdGVyaWEgdG8gZGV0ZXJtaW5lIHRoZSBvcmRlciBvZiBpbXBvcnRhbmNlIG9mIHRoZXNlIGF0dHJpYnV0ZXMuIEkgcmVsaWVkIG9uIHZpc3VhbGl6YXRpb24gYW5kIGNob3NlIHRoZSB2b2xhdGlsZSBhY2lkaWN5IGFzIHRoZSBtb3N0IHByb21pc2luZyBhdHRyaWJ1dGUgYW5kIHVzZWQgaXQgYXMgdGhlIGZpeGVkIGF0dHJpYnV0ZSBkdXJpbmcgbXVsdGl2YXJpYXRlIHBsb3Qgc2VjdGlvbi4KCkkgZGlkIG9ic2VydmUgc29tZSBnb29kIHJlc3VsdHMgd2hlbiBhbnN3ZXJpbmcgcXVlc3Rpb24gMi4gVGhlIHBsb3RzIHNob3dpbmcgYmV0d2VlbiBhbmQgYW1vbmcgZGlmZmVyZW50IGlucHV0IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzIHdlcmUgaW4gYWNjb3JkYW5jZSB3aXRoIGFjdHVhbCBwaHlzaWNhbCBhbmQgY2hlbWljYWwgcHJvcGVydGllcyBhbmQgbGF3cywgc3VjaCBoaWdoIGFjaWQgY29uY2VudHJhdGlvbiBjb3JyZWxhdGVzIHdpdGggbG93IHBILCBhbmQgaGlnaCBhbGNvaG9sIHBlcmNlbnQgY29ycmVsYXRlcyB3aXRoIGxvdyBkZW5zaXR5LgoKSSBiZWxpZXZlIGJ5IGluY29ycG9yYXRpbmcgb3RoZXIgdHlwZXMgb2YgYXR0cmlidXRlcywgc3VjaCBhcyBwcmljZSwgY29sb3IgYW5kIHNtZWxsLCBJIGNhbiBidWlsZCBhIGJldHRlciBtb2RlbCB0byBwcmVkaWN0IHRoZSBxdWFsaXR5IG9mIHdpbmUgdGhhbiB1c2luZyBvbmx5IHBoeXNpY29jaGVtaWNhbCBhdHRyaWJ1dGVzLiBBbHNvLCBvbmUgbW9yZSBpbnRlcmVzdGluZyBwcm9qZWN0IGNhbiBiZSBjb21iaW5pbmcgdGhlIHJlZCB3aW5lIGRhdGEgc2V0IHdpdGggdGhlIHdoaXRlIHdpbmUgZGF0YSBzZXQsIGFuZCB0byBmaW5kIG91dCBpZiBhdHRyaWJ1dGVzIGNvcnJlbGF0ZSB0byBoaWdoIHF1YWxpdHkgcmVkIHdpbmVzIGFsc28gY29ycmVsYXRlIHRvIGhpZ2ggcXVhbGl0eSB3aGl0ZSB3aW5lcy4=